﻿using ArtMath.CommonType.Converter;
using ArtMath.Component.Converter;
using ArtMath.Component.Line.Converter;
using ArtMath.Converter;
using ArtMath.Core.Converter;
using ArtMath.Flag;
using ArtMath.Parameter.Converter;
using ArtMath.Setting;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace ArtMath.Core.Helper
{
    /// <summary>
    /// 类库扩展方法
    /// </summary>
    public static class LibraryExtension
    {
        /// <summary>
        /// 判断一个double型变量是否是数字
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public static bool IsNumber(this double expression)
        {
            return !(double.IsNaN(expression) || double.IsInfinity(expression));
        }
        public static bool AlmostEqual(this double a, double b)
        {
            double abs = Math.Abs(a - b);
            return abs <= Settings.Instance.NumberEPS || abs <= Settings.Instance.NumberREPS * Math.Abs(a);
        }
        public static bool IsInteger(this double a)
        {
            return !a.ToString().Contains('.');
        }
        public static int BeforePointCount(this double a)
        {
            return (int)Math.Log10((long)a) + 1;
        }
        public static int AfterPointCount(this double a)
        {
            int sum = 0;
            while (!a.IsInteger())
            {
                a *= 10;
                sum++;
            }
            return sum;
        }
        public static void AddRange<T>(this HashSet<T> set, IEnumerable<T> collection)
        {
            if (collection == null) return;
            foreach (T item in collection)
            {
                set.Add(item);
            }
        }
        public static void InsertShortcutKey(this ToolStripDropDownItem menu)
        {
            int offset = 0;
            for (int i = 0; i < menu.DropDownItems.Count; i++)
            {
                ToolStripDropDownItem item = menu.DropDownItems[i] as ToolStripDropDownItem;
                if (item == null)
                {
                    offset--;
                }
                else
                {
                    item.Text = $"&{'A'.GetNextLetter(i + offset)}. {item.Text}";
                    item.InsertShortcutKey();
                }
            }
        }
        public static T[] GetAttributes<T>(this Type t, string memberName) where T : System.Attribute
        {
            object[] attr = null;
            MemberInfo[] mis;
            //一直搜到含有该特性的类
            while (t != typeof(object) && (mis = t.GetMember(memberName)) != null && mis.Length > 0 &&
                ((attr = mis[0].GetCustomAttributes(typeof(T), true)) == null || attr.Length == 0))
            {
                t = t.BaseType;
            }
            if (attr == null || attr.Length == 0) return null;
            T[] res = new T[attr.Length];
            for (int i = 0; i < res.Length; i++)
            {
                res[i] = attr[i] as T;
            }
            return res;
        }
        static readonly string[] notReachAsmNames = new string[]
        {
            $"{Flags.SoftwareName}.Animation.Converter", $"{Flags.SoftwareName}.Component.Annotation.Converter",
            $"{Flags.SoftwareName}.Component.CoordinateSystem.Converter", $"{Flags.SoftwareName}.Component.Point.Converter",
            $"{Flags.SoftwareName}.Data.Converter",
        };
        public static TypeConverter GetConverter(this Type t)
        {
            Type[] samples = new Type[] { typeof(FillStyleConverter), typeof(FunctionAbsorbRuleConverter),
                typeof(StringXConverter), typeof(UIColorThemeConverter), typeof(ParameterUnitConverter),
                typeof(TypeConverterBase), typeof(TypeConverter), t };
            TypeConverter res = null;
            foreach (Type sample in samples)
            {
                try
                {
                    res = Assembly.GetAssembly(sample).CreateInstance($"{sample.Namespace}.{t.Name}Converter") as TypeConverter;
                    if (res != null) return res;
                }
                catch (Exception)
                {
                }
            }
            Assembly asm;
            try
            {
                asm = Assembly.Load(Flags.SoftwareName);
            }
            catch (Exception)
            {
                return null;
            }
            foreach (string item in notReachAsmNames)
            {
                try
                {
                    res = asm.CreateInstance($"{item}.{t.Name}Converter") as TypeConverter;
                    if (res != null) return res;
                }
                catch (Exception)
                {
                }
            }
            return res;
        }
        public static string GetNextLetter(this char begin, int index)
        {
            if (index < 0) return begin.ToString();
            return GetNextLetter(begin, index / 26 - 1) + (char)(index % 26 + begin);
        }
        public static Color HSVOffset(this Color cl, float Hoffset, float Soffset, float Voffset, bool loop = false)
        {
            float newH = cl.GetHue() + Hoffset, newS = cl.GetSaturation() + Soffset, newV = cl.GetBrightness() + Voffset;
            if (loop)
            {
                newH %= 360;
                newS %= 1;
                newV %= 1;
            }
            else
            {
                if (Hoffset > 0)
                {
                    newH = Math.Min(newH, 359.999f);
                }
                else if (Hoffset < 0)
                {
                    newH = Math.Max(newH, 0);
                }
                if (Soffset > 0)
                {
                    newS = Math.Min(newS, 1);
                }
                else if (Soffset < 0)
                {
                    newS = Math.Max(newS, 0);
                }
                if (Voffset > 0)
                {
                    newV = Math.Min(newV, 1);
                }
                else if (Voffset < 0)
                {
                    newV = Math.Max(newV, 0);
                }
            }
            return Utility.HSVToRGB(newH, newS, newV);
        }
        public static Color GetGrayColor(this Color cl)
        {
            int gray = (int)(cl.R * 0.299 + cl.G * 0.587 + cl.B * 0.114);
            return Color.FromArgb(gray, gray, gray);
        }
        public static bool BaseColorEquals(this Color x, Color y)
        {
            return x.R == y.R && x.G == y.G && x.B == y.B;
        }
        public static Color GetReversedColor(this Color cl, bool revTrans = true)
        {
            return Color.FromArgb(revTrans ? 255 - cl.A : cl.A, 255 - cl.R, 255 - cl.G, 255 - cl.B);
        }
        public static void CrossThreadInvoke(this Control ctl, Action act)
        {
            if (act == null) return;
            if (ctl != null && ctl.InvokeRequired)
            {
                ctl.Invoke(act);
            }
            else
            {
                act();
            }
        }
        public static IEnumerable<ListViewItem> GetItems(this ListView lv, bool all)
        {
            if (all)
            {
                return lv.Items.OfType<ListViewItem>();
            }
            else
            {
                return lv.SelectedItems.OfType<ListViewItem>();
            }
        }
    }
}
